package com.bestv.search.engine.command;

import com.bestv.search.common.cache.SystemCache;
import com.bestv.search.common.dataSource.DataSourceKey;
import com.bestv.search.common.dataSource.DataSourceKeyUtil;
import com.bestv.search.common.model.TopKeyword;
import com.bestv.search.common.model.TopNCache;
import com.bestv.search.common.service.TopKeywordManager;
import com.bestv.search.common.util.StringConst;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.*;

/**
 * @author Michael Wang
 */

// $Id: TopNCommand.java 261 2013-07-24 07:36:57Z luo.xiaojun $
public class TopNCommand {
    protected final Log log = LogFactory.getLog(getClass());
    private TopKeywordManager topKeywordManager;
    private TopNCacheCommand topNCacheCommand;
    private SystemCache systemCache;

    public String topn(String type, boolean increase, int mergeType, int limit) {
        // Gets topKeywords
        List<TopKeyword> topKeywords = getTopNKeyword(type, increase, mergeType);

        // build response xml
        StringBuffer result = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?><result>");
        if (topKeywords != null && topKeywords.size() > 0) {
            int n = Math.min(limit, topKeywords.size());
            for (int i = 0; i < n; i++) {
                result.append("<record><keyword>").append(topKeywords.get(i).getKeyword().trim())
                        .append("</keyword><index>").append(i).append("</index></record>");
            }
        }
        result.append("</result>");
        return result.toString();
    }

    public String topnToJSON(String type, boolean increase, int mergeType, int limit) {
        // Gets topKeywords
        List<TopKeyword> topKeywords = getTopNKeyword(type, increase, mergeType);
        JSONArray array = new JSONArray();
        if (topKeywords != null && topKeywords.size() > 0) {
            int n = Math.min(limit, topKeywords.size());
            for (int i = 0; i < n; i++) {
                JSONObject json = new JSONObject();
                try {
                    json.put("keyword", topKeywords.get(i).getKeyword().trim());
                    json.put("index", i);
                } catch (JSONException e) {
                    log.equals("Convert TopKeyword to json object failed " + e);
                    e.printStackTrace();
                }
                array.put(json);
            }
        }
        return "{'result':" + array.toString() + "}";
    }

    public List<TopKeyword> getAllTopKeywords() {
        // Get local data source key
        DataSourceKey key = DataSourceKeyUtil.convert(systemCache.getLocalDataSourceKey());
        return topKeywordManager.getAllTopKeywords(key);
    }

    private List<TopKeyword> getTopNKeyword(String type, boolean increase, int mergeType) {
        if ("Merge".equalsIgnoreCase(type)) {
            if (mergeType == 1) {
                return getMergeType1TopNKeywords(increase);
            } else {
                log.error("Invalid merge type " + mergeType + ", from cmd topN");
                return null;
            }
        } else {

            List<TopNCache> list = topNCacheCommand.getTopNListFromCache(StringConst.KEYWORD, type, increase, null);
            return convert(list);
        }
    }

    private List<TopKeyword> getMergeType1TopNKeywords(boolean increase) {
        String[] types = new String[]{StringConst.WEEKLY, StringConst.MONTHLY, StringConst.QUARTER};
        List<TopKeyword> results = new ArrayList<TopKeyword>();

        // For map, key is string of keyword, value is TopKeywordScore
        Map<String, TopNCache> map = new HashMap<String, TopNCache>();
        for (String type : types) {
            // gets base score
            double baseScore = 0;
            if (StringConst.WEEKLY.equalsIgnoreCase(type)) {
                baseScore = 0.2;
            } else if (StringConst.MONTHLY.equalsIgnoreCase(type)) {
                baseScore = 0.3;
            } else {
                baseScore = 0.5;
            }

            List<TopNCache> list = topNCacheCommand.getTopNListFromCache(StringConst.KEYWORD, type, increase, null);

            // Gets keywords by key
            // List<TopKeyword> keywords = getTopNKeywordFromCache(key);
            // Convert keywords to TopKeywordScore
            int size = list.size();
            for (int i = 0; i < size; i++) {
                TopNCache cache = list.get(i);
                cache.setScore((i + 1) * baseScore);

                TopNCache cacheInMap = map.get(cache.getName());
                if (cacheInMap != null) {
                    // if scoreInMap.score is more bigger, replace it by new
                    if (cacheInMap.getScore() > cache.getScore()) {
                        map.put(cache.getName(), cache);
                    }
                } else {
                    map.put(cache.getName(), cache);
                }
            }
        }

        // Sort by score asc
        TopNCache[] array = map.values().toArray(new TopNCache[map.size()]);
        Arrays.sort(array, new Comparator<TopNCache>() {
            public int compare(TopNCache t1, TopNCache t2) {
                if (t1.getScore() > t2.getScore()) {
                    return 1;
                } else if (t1.getScore() < t2.getScore()) {
                    return -1;
                } else {
                    return t2.getName().compareTo(t1.getName());
                }
            }
        });

        // Convert to TopKeyword
        int n = array.length;
        for (int i = 0; i < n; i++) {
            TopNCache cache = array[i];
            TopKeyword keyword = new TopKeyword();
            keyword.setCount(cache.getThisCount());
            keyword.setKeyword(cache.getName());
            results.add(keyword);
        }

        return results;
    }

    private List<TopKeyword> convert(List<TopNCache> list) {
        // Convert to TopKeyword
        List<TopKeyword> result = new ArrayList<TopKeyword>();
        for (TopNCache cache : list) {
            TopKeyword keyword = new TopKeyword();
            keyword.setCount(cache.getThisCount());
            keyword.setKeyword(cache.getName());
            result.add(keyword);
        }

        return result;
    }

    // Start getter/setter method

    public TopKeywordManager getTopKeywordManager() {
        return topKeywordManager;
    }

    public void setTopKeywordManager(TopKeywordManager topKeywordManager) {
        this.topKeywordManager = topKeywordManager;
    }

    public SystemCache getSystemCache() {
        return systemCache;
    }

    public void setSystemCache(SystemCache systemCache) {
        this.systemCache = systemCache;
    }

    public TopNCacheCommand getTopNCacheCommand() {
        return topNCacheCommand;
    }

    public void setTopNCacheCommand(TopNCacheCommand topNCacheCommand) {
        this.topNCacheCommand = topNCacheCommand;
    }

    // End getter/setter method
}
